const fsPromise = require("fs/promises");
const path = require("path");
const { clone } = require("../util/clone");
const { mkdir } = require("../method/fs/mkdir");

/**
 * 操作缓存逻辑
 * 1. 检测到读写操作时开启缓存，设置缓存生效时长 cacheTime，缓存生效期间所有读写操作均在缓存内执行
 * 2. 检测到缓存失效时将缓存数据保存到文件，清空缓存
 */

/**
 * 本地数据库生成器
 * 使用本地文件作为数据库进行操作，只提供基础功能：文件初始化、操作缓存、整体读取、整体写入。
 * constructor函数接收如下参数：
 * @param {*} filePath 文件路径，必填
 * @param {*} defaultData 创建文件时需要填入文件的值，对象或者数组
 * @returns {*} database 数据库实例对象
 * @returns {*} database.getData() 获取数据
 * @returns {*} database.setData() 写入数据
 */
exports.DatabaseGenerator = class {
  /**
   * 缓存生效时长
   */
  cacheEffectTime = 1000;

  /**
   * 是否启用缓存
   */
  isUseCache = false;

  /**
   * 缓存期间是否有写操作
   */
  hasWriteOperate = false;

  /**
   * 数据缓冲区
   */
  cache = null;

  /**
   * 定时器timer
   */
  timer = null;

  /**
   * 文件目录
   */
  filePath = "";

  /**
   * 默认数据
   */
  defaultData = null;

  constructor(filePath, defaultData = {}) {
    if (!filePath) {
      throw new Error(`DatabaseGenerator Error：filePath is require`);
    }
    this.filePath = filePath;
    this.defaultData = defaultData;
  }

  getData() {
    // 节流
    clearTimeout(this.timer);
    if (this.isUseCache) {
      this.timer = setTimeout(this.clearCache.bind(this), this.cacheEffectTime);
      return this.cache;
    }

    let data = clone(this.defaultData);
    try {
      delete require.cache[require.resolve(this.filePath)];
      data = require(this.filePath);
    } catch (e) {
      this.createCollectionFile();
    }
    this.isUseCache = true;
    this.cache = data;
    return data;
  }

  async setData(data) {
    // 节流
    clearTimeout(this.timer);
    if (this.isUseCache) {
      // 更新缓存
      this.cache = data;
      this.hasWriteOperate = true;
      this.timer = setTimeout(this.clearCache.bind(this), this.cacheEffectTime);
      return;
    }

    return await fsPromise
      .writeFile(this.filePath, JSON.stringify(data), {
        encoding: "utf-8",
      })
      .then(() => {
        return true;
      })
      .catch(() => {
        console.log(`文件写入失败：${this.filePath}`);
        return false;
      });
  }

  /**
   * 清空缓存
   */
  clearCache() {
    this.isUseCache = false;
    if (this.hasWriteOperate) {
      this.setData(this.cache);
      this.hasWriteOperate = false;
    }
  }

  async createCollectionFile() {
    const dirname = path.dirname(this.filePath);
    await mkdir(dirname);
    fsPromise
      .writeFile(this.filePath, JSON.stringify(this.defaultData))
      .then(() => {
        console.log(`文件创建成功：${this.filePath}`);
      })
      .catch((error) => {
        console.log(`文件创建失败：${this.filePath}，${JSON.stringify(error)}`);
      });
  }
};
